

#include "GamePluginManager.h"
#include "EditorPlugin.h"
#include <QtCore/QtCore>

GamePluginManager GamePluginManager::msInstance;


GamePluginManager &GamePluginManager::instance()
{
    return msInstance;
}

GamePluginManager::GamePluginManager()
{
    
}

GamePluginManager::~GamePluginManager()
{
    
}

void GamePluginManager::initialize()
{
    QDir path = QDir(qApp->applicationDirPath());
    path.cd("Plugins");
    
    foreach(QFileInfo info, path.entryInfoList(QDir::Files | QDir::NoDotAndDotDot))
        load(info.absoluteFilePath());
}

void GamePluginManager::uninitialize()
{
    foreach(const QString &path, mLoaders.keys())
        unload(path);
}

void GamePluginManager::scan(const QString &path)
{
    if (!QLibrary::isLibrary(path))
    {
        return;
    }
    
    QPluginLoader *loader = new QPluginLoader(path);
    mNames.insert(path, loader->metaData().value("MetaData").toObject().value("name").toVariant());
    mVersions.insert(path, loader->metaData().value("MetaData").toObject().value("version").toVariant());
    mDependencies.insert(path, loader->metaData().value("MetaData").toObject().value("dependencies").toArray().toVariantList());
    delete loader;
}

void GamePluginManager::load(const QString &path)
{
    if (!QLibrary::isLibrary(path))
    {
        return;
    }
    
    if (!check(path))
    {
        return;
    }
    
    QPluginLoader *loader = new QPluginLoader(path);
    if (EditorPlugin *plugin = qobject_cast<EditorPlugin *>(loader->instance()))
    {
		QString name = plugin->name();
		mNames.insert(name, loader->metaData().value("MetaData").toObject().value("name").toVariant());
		mVersions.insert(name, loader->metaData().value("MetaData").toObject().value("version").toVariant());
		mDependencies.insert(name, loader->metaData().value("MetaData").toObject().value("dependencies").toArray().toVariantList());
        mLoaders.insert(name, loader);
    }
    else
    {
        delete loader;
    }
}

void GamePluginManager::unload(const QString &path)
{
    QPluginLoader *loader = mLoaders.value(path);
    
    if (loader->unload())
    {
        mLoaders.remove(path);
        delete loader;
    }
}

QLoaderList GamePluginManager::plugins()
{
    return mLoaders.values();
}


EditorPlugin *GamePluginManager::pluginInstance(const QString &name)
{
    return qobject_cast<EditorPlugin*>(mLoaders[name]->instance());
}

EditorPlugin *GamePluginManager::pluginInstance(uint pluginID)
{
	QHash<QString, QPluginLoader*>::Iterator itr = mLoaders.begin();

	while (itr != mLoaders.end())
	{
		EditorPlugin *plugin = qobject_cast<EditorPlugin*>((*itr)->instance());
		if (plugin != 0 && plugin->pluginID() == pluginID)
		{
            return plugin;
		}
		++itr;
	}

	return 0;
}

bool GamePluginManager::check(const QString &path)
{
    bool status = true;
 
    foreach(QVariant item, mDependencies.value(path))
    {
        QVariantMap mitem = item.toMap();
        QVariant na_mitem = mitem.value("name");
        QVariant ve_mitem = mitem.value("version");
        QString key = mNames.key(na_mitem);
        
        if (!mNames.values().contains(na_mitem))
        {
            qDebug() << Q_FUNC_INFO << "  Missing dependency:" << na_mitem.toString() << "for plugin" << path;
            status = false;
            continue;
        }
        
        if (mVersions.value(key) != ve_mitem)
        {
            qDebug() << Q_FUNC_INFO << "    Version mismatch:" << na_mitem.toString() << "version" << mVersions.value(mNames.key(na_mitem)).toString() << "but" << ve_mitem.toString() << "required for plugin" << path;
            status = false;
            continue;
        }
        
        if (!check(key))
        {
            qDebug() << Q_FUNC_INFO << "Corrupted dependency:" << na_mitem.toString() << "for plugin" << path;
            status = false;
            continue;
        }
    }
    
    return status;
}

